/*
 * Copyright 2007. Mount Sinai Hospital, Toronto, Canada.
 * 
 * Licensed under the GNU Lesser General Public License, Version 2. You
 * can find a copy of the license at:
 * 
 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
 * 
 * IN NO EVENT SHALL MOUNT SINAI HOSPITAL BE LIABLE TO ANY PARTY FOR DIRECT, 
 * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST 
 * PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, 
 * EVEN IF MOUNT SINAI HOSPITAL HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 
 * DAMAGE.
 * 
 * MOUNT SINAI HOSPITAL SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF 
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE AND 
 * ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". 
 * MOUNT SINAI HOSPITAL HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, 
 * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 
 */
package com.sinai.mshab.client.util;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;

import com.google.gwt.user.client.rpc.IsSerializable;
import com.sinai.mshab.client.MSHABConfig;

/**
 * <code>AnswerCollection</code> maintains a collection of {@link Answer}
 * objects and acts similar to an {@link ArrayList}.
 * 
 * @see ArrayList
 * @author Arthur Kalmenson
 */
public class AnswerCollection implements IsSerializable {

	/**
	 * The list of <code>Answer</code>s. <b>Note:</b> This
	 * <code>ArrayList</code> can only contain <code>Answer</code> objects.
	 * 
	 * @gwt.typeArgs <com.sinai.mshab.client.util.Answer>
	 */
	private ArrayList answers;

	/**
	 * Creates a new empty <code>AnswerCollection</code>.
	 */
	public AnswerCollection() {
		answers = new ArrayList();
	}

	/**
	 * Creates a new <code>AnswerCollection</code> and adds
	 * <code>first_answer</code>.
	 * 
	 * @param first_answer
	 *            the initial <code>Answer</code> to add to the new
	 *            <code>AnswerCollection</code>.
	 */
	public AnswerCollection(Answer first_answer) {
		answers = new ArrayList();
		answers.add(first_answer);
	}

	/**
	 * Adds <code>answer</code> to the current <code>AnswerCollection</code>.
	 * 
	 * @param answer
	 *            the <code>Answer</code> to add.
	 */
	public void add(Answer answer) {
		if (answer == null) {
			throw new IllegalArgumentException(
					MSHABConfig.MSHAB_ERROR_NULL_ARGS);
		}
		answers.add(answer);
	}

	/**
	 * Returns the <code>Answer</code> object at index <code>index</code>.
	 * 
	 * @param index
	 *            the index of the requested <code>Answer</code> object.
	 * @return the <code>Answer</code> object at index <code>index</code>.
	 */
	public Answer get(int index) {
		if (index < answers.size()) {
			return (Answer) answers.get(index);
		}

		return null;
	}

	/**
	 * Returns the size of the current <code>AnswerCollection </code>.
	 * 
	 * @return the size of the current <code>AnswerCollection </code>.
	 */
	public int size() {
		return answers.size();
	}

	/**
	 * Returns whether this <code>AnswerCollection</code> is empty or not. It
	 * is considered empty if all of it's containing {@link Answer}s are empty.
	 * 
	 * @return whether this <code>AnswerCollection</code> is empty or not.
	 */
	public boolean isEmpty() {

		return answers.isEmpty();
	}

	/**
	 * Condesnses all answer objects into fewer answer objects by merging
	 * mergable answers of the same table name into 1 answer.
	 */
	public void pack() {
		HashMap table_to_answer = new HashMap();

		// going through all of our answers and grouping them based on table
		// name
		for (int i = 0; i < answers.size(); i++) {
			Answer current_answer = (Answer) answers.get(i);
			
			// if the current answer is empty, we don't include it in the pack.
			if (current_answer.isEmpty()) {
				continue;
			}
			String table_name = current_answer.getTableName();

			// if the key already exists
			if (table_to_answer.containsKey(table_name)) {

				// if this answer is not mergable, simply append it to the list
				if (!current_answer.isMergeable()) {
					ArrayList answers_for_current_table = (ArrayList) table_to_answer
							.get(table_name);
					answers_for_current_table.add(current_answer);
				}
				// if this IS mergable, find the first mergable answer object
				// and merge with it
				else {
					ArrayList answers = (ArrayList) table_to_answer
							.get(table_name);
					for (int j = 0; j < answers.size(); j++) {
						Answer a = (Answer) answers.get(j);
						if (a.isMergeable()) {
							a.add(current_answer);
						}
					}
				}
			}
			// if the key does not exist, add a new entry
			else {
				ArrayList answers = new ArrayList();
				answers.add(current_answer);
				table_to_answer.put(table_name, answers);
			}
		}

		// place the merged answers back into our arraylist
		ArrayList new_answers = new ArrayList();
		Iterator it = table_to_answer.keySet().iterator();
		while (it.hasNext()) {
			ArrayList an = (ArrayList) table_to_answer.get(it.next());
			for (int i = 0; i < an.size(); i++) {
				new_answers.add(an.get(i));
			}
		}

		// replace old answer objects with new ones.
		this.answers = new_answers;
	}
}
